package com.yxw.live_vod_boot.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yxw.live_vod_boot.dto.*;
import com.yxw.live_vod_boot.entity.*;
import com.yxw.live_vod_boot.enums.MqttTopicEnum;
import com.yxw.live_vod_boot.mapper.*;
import com.yxw.live_vod_boot.mqtt.MqttGateway;
import com.yxw.live_vod_boot.service.LoginService;
import com.yxw.live_vod_boot.service.LiveRecommendService;
import com.yxw.live_vod_boot.utils.*;
import com.yxw.live_vod_boot.vo.LoginUserVo;
import com.yxw.live_vod_boot.vo.MqttInforSystemVO;
import com.yxw.live_vod_boot.vo.UserInfoVo;
import com.yxw.live_vod_boot.vo.UserTokenVo;
import com.yxw.yxnet_cd_center.common.constant.CommonConstant;
import com.yxw.yxnet_cd_center.common.constant.RedisIdConstant;
import com.yxw.yxnet_cd_center.common.dto.BaseDTO;
import com.yxw.yxnet_cd_center.common.dto.HuaWeiSmsDTO;
import com.yxw.yxnet_cd_center.common.enums.CommonErrorEnum;
import com.yxw.yxnet_cd_center.common.enums.NoticeTypeEnum;
import com.yxw.yxnet_cd_center.common.exception.BaseException;
import com.yxw.yxnet_cd_center.common.result.TokenInfo;
import com.yxw.yxnet_cd_center.common.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Pattern;

/**
 *  直播平台登录注册管理
 * @author liuxin
 * @date 2023.11.29
 */
@Service
@Slf4j
public class LoginServiceImpl  implements LoginService {


    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisManager redisManager;

    @Autowired
    private ChannelMapeer channelMapeer;

    @Autowired
    private UserUtil userUtil;

    @Autowired
    private HuaWeiSmsUtil smsComponent;

    @Autowired
    private SmsTemplateMapper smsTemplateMapper;

    @Autowired
    private MqttGateway mqttGateway;

    @Autowired
    private ShopMapper shopMapper;

    @Autowired
    private YxLiveShopUserMapper yxLiveShopUserMapper;

    @Autowired
    private UserCancelMapper userCancelMapper;

    @Autowired
    private LiveRecommendService liveRecommendService;

    /**
     * 外部接口登录授权
     * @param token
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResult authLogin(String token)  {
        try {
            log.info("平台授权登录加密参数:{}", token);
            //解密token,AES128解密
            token = AESUtil.decrypt(token);
            log.info("平台授权登录解密信息:{}", token);
            //解析参数
            AuthLoginDTO dto = JSON.parseObject(token, AuthLoginDTO.class);
            //非空参数校验
            String errMsg=this.validataAuthDto(dto);
            if(StringUtils.isNotBlank(errMsg)){
                throw new BaseException(CommonErrorEnum.PARAM_ERROR,errMsg);
            }
            //校验注销时间
            this.validataLogAff(dto.getPhone());
            //查询电话是否注册
            LambdaQueryWrapper<YxSysUserEntity> userWrapper = new LambdaQueryWrapper();
            userWrapper.eq(true,YxSysUserEntity::getPhone,dto.getPhone());
            YxSysUserEntity userEntity = userMapper.selectOne(userWrapper);
            //首次/注册后登录绪重新创建账号
            if(null==userEntity){
                //新增人员信息
                userEntity = new YxSysUserEntity();
                userEntity.setPhone(dto.getPhone());
                userEntity.setOutUserAccount(dto.getUserAccount());
                userEntity.setStatus(CommonConstant.ONE);
                userEntity.setLiveCode(BaseDateTime.getLongDateTimeStringNoSlipt(new Date()));
                userEntity.setCreateTime(new Date());
                userEntity.setUpdateTime(new Date());
                userEntity.setUserName(dto.getUserName());
                userEntity.setOutNickName(dto.getUserName());
                //默认昵称
                userEntity.setNickName("yx_"+ String.format("%08d",new Random().nextInt(10000000)));
                //渠道查询
                LambdaQueryWrapper<YxSysChannelEntity> queryWrapper=new LambdaQueryWrapper();
                queryWrapper.eq(true,YxSysChannelEntity::getChannelCode,dto.getChannelCode())
                        .eq(true,YxSysChannelEntity::getAuthToken,dto.getAuthToken())
                        .eq(YxSysChannelEntity::getStatus,CommonConstant.ONE);
                YxSysChannelEntity yxSysChannel = channelMapeer.selectOne(queryWrapper);
                userEntity.setChannelName(yxSysChannel.getChannelName());
                userEntity.setChannelCode(yxSysChannel.getChannelCode());
                userEntity.setChannelId(yxSysChannel.getChannelId());
                userEntity.setSource(CommonConstant.ZERO);
                userMapper.insert(userEntity);
            }else{
                if(CommonConstant.ZERO==userEntity.getStatus()){
                    throw new BaseException(CommonErrorEnum.PARAM_ERROR,"直播平台已禁用该账号,请联系管理员处理！");
                }
            }
            //店铺校验
            List<RegisterShopDto> shopInfoList = dto.getShopInfoList();
            if(null!=shopInfoList && !shopInfoList.isEmpty()) {
                for (RegisterShopDto shop : shopInfoList) {
                    //店铺信息注册
                    LambdaQueryWrapper<YxLiveShopEntity> shopWrapper = new LambdaQueryWrapper();
                    shopWrapper.eq(YxLiveShopEntity::getShopId, shop.getShopId());
                    YxLiveShopEntity shopEntity = shopMapper.selectOne(shopWrapper);
                    if (null == shopEntity) {
                        //店铺注册到平台以后
                        shopEntity = new YxLiveShopEntity();
                        BeanUtils.copyProperties(shop, shopEntity);
                        shopEntity.setRemainStorage(new BigDecimal(0));
                        //生成视频号
                        shopEntity.setLiveCode(BaseDateTime.getLongDateTimeStringNoSlipt(new Date()));
                        shopEntity.setLiveCoin(BigDecimal.valueOf(0));
                        shopEntity.setStorage(new BigDecimal(0));
                        shopEntity.setCreateTime(new Date());
                        shopEntity.setUpdateTime(new Date());
                        shopEntity.setChannelId(userEntity.getChannelId());
                        shopEntity.setChannelCode(userEntity.getChannelCode());
                        shopEntity.setChannelName(userEntity.getChannelName());
                        shopEntity.setUserId(userEntity.getUserId());
                        shopEntity.setUserName(userEntity.getUserName());
                        shopEntity.setPhone(userEntity.getPhone());
                        shopMapper.insert(shopEntity);
                    }
                    //写店铺和人员关系中间表
                    LambdaQueryWrapper<YxLiveShopUserEntity> shopUserWrapper=new LambdaQueryWrapper();
                    shopUserWrapper.eq(YxLiveShopUserEntity::getShopUserId,userEntity.getUserId());
                    shopUserWrapper.eq(YxLiveShopUserEntity::getShopId,shopEntity.getShopId());
                    YxLiveShopUserEntity shopUserEntity = yxLiveShopUserMapper.selectOne(shopUserWrapper);
                    if(null==shopUserEntity){
                        shopUserEntity=new YxLiveShopUserEntity();
                        shopUserEntity.setShopId(shopEntity.getShopId());
                        shopUserEntity.setCreateUserId(userEntity.getUserId().toString());
                        shopUserEntity.setUserType(CommonConstant.ZERO);
                        shopUserEntity.setShopUserId(userEntity.getUserId().toString());
                        shopUserEntity.setCreateTime(new Date());
                        shopUserEntity.setUpdateTime(new Date());
                        yxLiveShopUserMapper.insert(shopUserEntity);
                    }
                }
            }
            LoginUserVo vo =this.getLoginUserVo(userEntity);
            liveRecommendService.liveUserCacheInit(userEntity.getUserId());
            return BaseResult.success("0000",AESUtil.encrypt(JSON.toJSONString(vo)));
        } catch (Exception e) {
            log.error("平台授权登录异常:{}", e.getMessage());
            if(e instanceof BaseException){
                throw (BaseException)e;
            }
            throw new BaseException(CommonErrorEnum.DATA_SERVICE_CALL_FAILED,e.getMessage());
        }
    }

    /**
     * 登出
     * @param baseDTO
     */
    @Override
    public void logout(BaseDTO baseDTO) {
        UserTokenVo userTokenVo = (UserTokenVo) redisManager.get(RedisIdConstant.LOGIN_TOKEN + userUtil.getLoginUserId());
        if(userTokenVo != null) {
            redisManager.del(RedisIdConstant.LOGIN_TOKEN + userUtil.getLoginUserId());
        }
    }

    /**
     * 账号密码登录
     * @param userLoginDTO
     * @return
     */
    @Override
    public LoginUserVo login(UserLoginDTO userLoginDTO){
        this.validataLogAff(userLoginDTO.getPhone());
        //用户信息
        YxSysUserEntity user = userMapper.selectOne(new LambdaQueryWrapper<YxSysUserEntity>()
                .eq(YxSysUserEntity::getPhone, userLoginDTO.getPhone())
                .eq(YxSysUserEntity::getStatus, CommonConstant.ONE)
        );
        if(StringUtils.isBlank(user.getPwd())){
            throw new BaseException("账号密码还未设置,请点击找回密码设置登陆密码");
        }
        //账号不存在、密码错误
        if(user == null || !Objects.equals(PasswordUtil.signUserPassword(user.getUserId(),userLoginDTO.getPassword()), user.getPwd())) {
            throw new BaseException("账号或密码不正确");
        }
        //发送异地登录提醒,下线已登录账号
        this.sendOfflineNotice(user);
        LoginUserVo loginUserVo = getLoginUserVo(user);
        liveRecommendService.liveUserCacheInit(user.getUserId());
        return loginUserVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LoginUserVo phone(UserPhoneLoginDTO userPhoneLoginDTO) {
        String code = (String) redisManager.get(RedisIdConstant.LOGIN_SMS_CODE + userPhoneLoginDTO.getMobilePhone());
        if(!userPhoneLoginDTO.getCode().equals(code)){
            throw new BaseException(CommonErrorEnum.SMS_VERIFICATION_CODE);
        }
        YxSysUserEntity user = userMapper.selectOne(new LambdaQueryWrapper<YxSysUserEntity>()
                .eq(YxSysUserEntity::getPhone, userPhoneLoginDTO.getMobilePhone())
                .eq(YxSysUserEntity::getStatus, CommonConstant.ONE)
        );
        if(user == null) {
            //手机号登录没有就创建账号
            user = new YxSysUserEntity();
            user.setPhone(userPhoneLoginDTO.getMobilePhone());
            user.setStatus(CommonConstant.ONE);
            user.setCreateTime(new Date());
            user.setUpdateTime(new Date());
            user.setOutNickName("");
            //默认昵称
            user.setNickName("yx_"+ String.format("%08d",new Random().nextInt(10000000)));
            user.setUserName(user.getNickName());
            //渠道查询
            LambdaQueryWrapper<YxSysChannelEntity> queryWrapper=new LambdaQueryWrapper();
            queryWrapper.eq(true,YxSysChannelEntity::getChannelCode,"live_vod_app")
                    .eq(YxSysChannelEntity::getStatus,CommonConstant.ONE);
            YxSysChannelEntity yxSysChannel = channelMapeer.selectOne(queryWrapper);
            user.setChannelName(yxSysChannel.getChannelName());
            user.setChannelCode(yxSysChannel.getChannelCode());
            user.setChannelId(yxSysChannel.getChannelId());
            user.setSource(CommonConstant.ONE);
            userMapper.insert(user);
        }
        //发送异地登录提醒,下线已登录账号
        this.sendOfflineNotice(user);
        LoginUserVo loginUserVo = getLoginUserVo(user);
        liveRecommendService.liveUserCacheInit(user.getUserId());
        return loginUserVo;
    }

    /**
     *
     * @param userSendCodeDTO
     */
    @Override
    public String send(UserSendCodeDTO userSendCodeDTO) {
        //校验是否过了注销时间
        this.validataLogAff(userSendCodeDTO.getPhone());
        String code = RandomUtil.randomNumbers(6);
        redisManager.set(RedisIdConstant.LOGIN_SMS_CODE + userSendCodeDTO.getPhone(), code, 5 * 60);
        //查询模板配置
        LambdaQueryWrapper<YxVodSmsTemplateEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(YxVodSmsTemplateEntity::getTemplateCode, NoticeTypeEnum.SMS_CODE.getTemplateCode());
        YxVodSmsTemplateEntity entity = smsTemplateMapper.selectOne(wrapper);
        if(null==entity){
            throw new BaseException("短信模板未配置");
        }
        HuaWeiSmsDTO dto=new HuaWeiSmsDTO();
        dto.setTemplateParas("[\"" + code +"\"]");
        dto.setPhone(userSendCodeDTO.getPhone());
        dto.setSender(entity.getSender());
        dto.setTemplateId(entity.getHwTemplateId());
//        smsComponent.sendSmsCode(dto);
        return code;
    }

    /**
     * 刷新token接口
     * @param request
     * @return
     */
    @Override
    public LoginUserVo refreshToken(HttpServletRequest request) {
        //获取请求头token信息
        Cookie[] cookies = request.getCookies();
        if(null==cookies || cookies.length==0){
            throw new BaseException(CommonErrorEnum.REQUEST_HEADER_GET_TOKEN_EXCEPTION);
        }
        String token="";
        for (Cookie cookie:cookies) {
            if(CommonConstant.TOKEN.equals(cookie.getName())){
                token=cookie.getValue();
            }
        }
        if(StringUtils.isBlank(token)){
            throw new BaseException(CommonErrorEnum.REQUEST_HEADER_GET_TOKEN_EXCEPTION);
        }
        //解析token
        TokenInfo tokenInfo = TokenUtil.getTokenInfoByToken(token);
        Long userId = tokenInfo.getUserId();
        YxSysUserEntity user = userMapper.selectOne(new LambdaQueryWrapper<YxSysUserEntity>()
                .eq(YxSysUserEntity::getUserId, userId)
                .eq(YxSysUserEntity::getStatus, CommonConstant.ONE)
        );
        if(null==user){
            throw new BaseException(CommonErrorEnum.VERIFY_USER_TOKEN_EXCEPTION);
        }
        return getLoginUserVo(user);
    }

    /**
     * 密码找回验证码获取
     * @param userSendCodeDTO
     */
    @Override
    public String pwdSend(UserSendCodeDTO userSendCodeDTO) {
        //先校验账号是否存在
        YxSysUserEntity user = userMapper.selectOne(new LambdaQueryWrapper<YxSysUserEntity>()
                .eq(YxSysUserEntity::getPhone, userSendCodeDTO.getPhone())
                .eq(YxSysUserEntity::getStatus, CommonConstant.ONE)
        );
        if(user == null) {
            throw new BaseException("账号不存在或已禁用");
        }
        String code = RandomUtil.randomNumbers(6);
        redisManager.set(RedisIdConstant.UPDATE_PWD_SMS_CODE + userSendCodeDTO.getPhone(), code, 5 * 60);
        //查询模板配置
        LambdaQueryWrapper<YxVodSmsTemplateEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(YxVodSmsTemplateEntity::getTemplateCode, NoticeTypeEnum.UPDATE_PWD_SMS_CODE.getTemplateCode());
        YxVodSmsTemplateEntity entity = smsTemplateMapper.selectOne(wrapper);
        if(null==entity){
            throw new BaseException("短信模板未配置");
        }
        HuaWeiSmsDTO dto=new HuaWeiSmsDTO();
        dto.setTemplateParas("[\"" + code +"\"]");
        dto.setPhone(userSendCodeDTO.getPhone());
        dto.setSender(entity.getSender());
        dto.setTemplateId(entity.getHwTemplateId());
//        smsComponent.sendSmsCode(dto);
        return code;
    }

    /**
     * 通过手机号修改密码
     * @param dto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePwdByPhone(UpdatePwdDTO dto) {
        YxSysUserEntity user = userMapper.selectOne(new LambdaQueryWrapper<YxSysUserEntity>()
                .eq(YxSysUserEntity::getPhone, dto.getPhone())
                .eq(YxSysUserEntity::getStatus, CommonConstant.ONE)
        );
        if(null==user){
            throw new BaseException("请先登陆注册账号");
        }
        if(StringUtils.isNotBlank(user.getPwd())){
            //原密码不为空时，校验新密码是否与老密码相同
            if(Objects.equals(PasswordUtil.signUserPassword(user.getUserId(),dto.getPwd()), user.getPwd())){
                throw new BaseException("新密码不能与旧密码相同");
            }
        }
        user.setPwd(PasswordUtil.signUserPassword(user.getUserId(),dto.getPwd()));
        user.setUpdateTime(new Date());
        userMapper.updateById(user);
    }

//--------------------------------------------------------------------------------------------------------------

    /**
     * 外部登录注册认证参数校验
     *
     * @param dto
     */
    private String validataAuthDto(AuthLoginDTO dto) {
        StringBuffer sbf=new StringBuffer();
        if(StringUtils.isBlank(dto.getUserAccount())){
            sbf.append("人员账号[userAccount]不能为空！");
        }
        if(StringUtils.isBlank(dto.getUserName())){
            sbf.append("人员名称[userName]不能为空！");
        }
        String phone = dto.getPhone();
        if(StringUtils.isBlank(phone)){
            sbf.append("人员电话[phone]不能为空！");
        }else{
            //电话号码格式校验
            boolean matches = Pattern.matches("^1[3-9]\\d{9}$", phone);
            if(!matches){
                sbf.append("人员电话[phone]格式错误,请检查是否为11位国内三大运营商号码！");
            }
        }
        if(StringUtils.isBlank(dto.getChannelCode())){
            sbf.append("人员来源渠道[channelCode]不能为空！");
        }
        if(StringUtils.isBlank(dto.getAuthToken())){
            sbf.append("认证串[AuthToken]不能为空！");
        }
        //没有报错才校验数据合法性
        if(StringUtils.isBlank(sbf.toString())){
            //校验渠道和雁验证token是否合法
            LambdaQueryWrapper<YxSysChannelEntity> queryWrapper=new LambdaQueryWrapper();
            queryWrapper.eq(true,YxSysChannelEntity::getChannelCode,dto.getChannelCode())
                    .eq(true,YxSysChannelEntity::getAuthToken,dto.getAuthToken())
                    .eq(YxSysChannelEntity::getStatus,CommonConstant.ONE);
            YxSysChannelEntity yxSysChannel = channelMapeer.selectOne(queryWrapper);
            if(null==yxSysChannel){
                sbf.append("渠道编码[channelCode]和认证串[authToken]不匹配或该渠道已被禁止接入");
            }
        }
        //店铺校验
        List<RegisterShopDto> shopInfoList = dto.getShopInfoList();
        if(null!=shopInfoList && !shopInfoList.isEmpty()){
            for (RegisterShopDto shopInfo:shopInfoList) {
                String shopId = shopInfo.getShopId();
                String shopName = shopInfo.getShopName();
                if(StringUtils.isBlank(shopId) || StringUtils.isBlank(shopName) ){
                    sbf.append("携带店铺ID/名称缺失");
                }
            }
        }
        return sbf.toString();
    }

    /**
     * 登录返回信息
     * @param user
     * @return
     */
    private LoginUserVo getLoginUserVo(YxSysUserEntity user) {
        LoginUserVo loginUserVo = new LoginUserVo();
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtil.copyProperties(user, userInfoVo);
        long checkCode = System.currentTimeMillis();
        UserTokenVo userTokenVo = new UserTokenVo();
        userTokenVo.setId(user.getUserId());
        BeanUtil.copyProperties(user, userTokenVo);
        userTokenVo.setCheckCode(checkCode);
        userTokenVo.setExpirationDate(LocalDateTime.now().plusMinutes(30));
        userTokenVo.setMobilePhone(user.getPhone());
        String token = JwtUtil.generateToken(userTokenVo, checkCode);
        loginUserVo.setUser(userInfoVo);
        loginUserVo.setToken(token);
        UserTokenVo tokenVo = (UserTokenVo) redisManager.get(RedisIdConstant.LOGIN_TOKEN + user.getUserId());
        if(tokenVo != null) {
            redisManager.del(RedisIdConstant.LOGIN_TOKEN + user.getUserId());
        }
        redisManager.set(RedisIdConstant.LOGIN_TOKEN + user.getUserId(), userTokenVo, 60 * 60);
        return loginUserVo;
    }
    /**
     * 发送用户下线通知
     */
    private void sendOfflineNotice(YxSysUserEntity user) {
        MqttInforSystemVO systemVO = new MqttInforSystemVO();
        systemVO.setContent("该账号在别的地方登录,如非本人操作,请尽快修改登录密码");
        systemVO.setMsgType("sys");
        systemVO.setContentType("offline");
        systemVO.setRecv(String.valueOf(user.getUserId()));
        //下线操作
        systemVO.setNotificationType("offline");
        mqttGateway.sendToMqtt(MqttTopicEnum.SYSTEM_OFFLINE_TOPIC.getTopic() + user.getUserId(), JsonUtils.toJson(systemVO));
    }

    /**
     * 校验30天内是否存在注销账号,存在就提示
     */
   private  void validataLogAff(String phone){
        LambdaQueryWrapper<YxSysUserCancelEntity> queryWrapper=new LambdaQueryWrapper();
       queryWrapper.eq(YxSysUserCancelEntity::getPhone,phone);
       //获取30天前时间
       Calendar now = Calendar.getInstance();
       now.add(Calendar.DAY_OF_MONTH, -30);
       String beforDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(now.getTime());
       queryWrapper.ge(YxSysUserCancelEntity::getCreateTime,BaseDateTime.getDate(beforDate));
       List<YxSysUserCancelEntity> yxSysUserCancelEntities = userCancelMapper.selectList(queryWrapper);
       if(null!=yxSysUserCancelEntities && !yxSysUserCancelEntities.isEmpty()){
           throw new BaseException(CommonErrorEnum.PARAM_ERROR,"该账户在30天内存在注销行为,本次不允许注册登录");
       }
   }

    public static void main(String[] args) throws Exception {
        List<RegisterShopDto> shopInfoList=new ArrayList<>();
        RegisterShopDto r = new RegisterShopDto();
        r.setShopId("102");
        r.setShopName("注销店铺测试");
        shopInfoList.add(r);
        AuthLoginDTO dto = new AuthLoginDTO();
        dto.setAuthToken("yxnet@cd#2023");
        dto.setUserAccount("10088");
        dto.setUserName("王五");
        dto.setChannelCode("yxnet");
        dto.setPhone("18383117457");
        dto.setShopInfoList(shopInfoList);
        System.out.println(AESUtil.encrypt(JsonUtils.toJson(dto)));
        System.out.println(AESUtil.decrypt(AESUtil.encrypt(JsonUtils.toJson(dto))));
    }


}


